/**
 * 
 */
package netz.test.signup;

import java.util.List;

import com.google.code.netz.wfe.api.IWorkflowContext;
import com.google.code.netz.wfe.model.AbstractCase;
import com.google.code.netz.wfe.model.ICase;
import com.google.code.netz.wfe.model.ITask;
import com.google.code.netz.wfe.model.IToken;
import com.google.code.netz.wfe.model.InputArc;
import com.google.code.netz.wfe.model.OutputArc;
import com.google.code.netz.wfe.model.Place;
import com.google.code.netz.wfe.model.Transition;

/**
 * ICase that defines a process to sign up a new User.
 * 
 * @author <a href='mailto:rahul.thakur.xdev@gmail.com'>Rahul Thakur</a>
 * @since 1.0
 * @version $Id: SignupUserWorkflow.java 17 2009-02-09 13:08:49Z
 *          rahul.thakur.xdev $
 */
public class SignupUserWorkflow<D> extends AbstractCase<D> implements ICase<D> {

	/* Places declaration. */
	private Place<UserData> _start = new Place<UserData>("start");
	private Place<UserData> p2 = new Place<UserData>("Valid User Details");
	private Place<UserData> p3a = new Place<UserData>("Error Saving User");
	private Place<UserData> p3b = new Place<UserData>("User saved");
	private final Place<UserData> _end = new Place<UserData>("end");

	/* Transitions declaration. */
	private final Transition<UserData> t1 = new Transition<UserData>("Validate User Details", new ITask() {

		@Override
		public void execute(IWorkflowContext workflowContext) {
			System.out.println("Validating user details...");
			// TODO: Do something here to validate!
			System.out.println("User details validated!");
			p2.addToken(new IToken() {

				@Override
				public Object getData() {
					// TODO Auto-generated method stub
					return null;
				}
			});

		}

	});

	/**
	 * User details not saved.
	 */
	private boolean error = false;

	private final Transition<UserData> t2 = new Transition<UserData>("Save User Details", new ITask() {

		@Override
		public void execute(IWorkflowContext workflowContext) {
			System.out.println("Saving user details...");
			// TODO: Do something here to validate!
			System.out.println("User details saved!");

			Place p;

			if (error)
				p = p3a;
			else
				p = p3b;

			p.addToken(new IToken() {

				@Override
				public Object getData() {
					// TODO Auto-generated method stub
					return null;
				}
			});
		}

	});

	private final Transition<UserData> t3 = new Transition<UserData>("Display Result of Signup", new ITask() {

		@Override
		public void execute(IWorkflowContext workflowContext) {
			if (!error) {
				System.out.println("Displaying results...");
				// TODO: Do something here to validate!
				System.out.println("Results displayed!");
			} else {
				List<InputArc<?>> inputs = t3.getInputs();
				Place selectedInput = null;
				for (InputArc<?> input : inputs) {
					if (input.getSource().getTokens().size() > 0) {
						selectedInput = input.getSource();
						break;
					}
				}

				System.out.println("Picked up Token from Place: " + selectedInput.getLabel());
				System.out.println("Displaying sign up errors...");
				// TODO: Do something here to validate!
				System.out.println("Error displayed!");
			}

			_end.addToken(new IToken() {

				@Override
				public Object getData() {
					// TODO Auto-generated method stub
					return null;
				}
			});

		}

	});

	private final Transition<UserData> t4 = new Transition<UserData>("Display Error from Signup", new ITask() {

		@Override
		public void execute(IWorkflowContext workflowContext) {
			System.out.println("Displaying sign up errors...");
			// TODO: Do something here to validate!
			System.out.println("Error displayed!");

			_end.addToken(new IToken() {

				@Override
				public Object getData() {
					// TODO Auto-generated method stub
					return null;
				}
			});

		}

	});

	/* Input Arcs and Output Arcs declaration. */
	private InputArc<UserData> i1 = new InputArc<UserData>(_start, t1);
	private OutputArc<UserData> o1 = new OutputArc<UserData>(t1, p2);

	private InputArc<UserData> i2 = new InputArc<UserData>(p2, t2);
	private OutputArc<UserData> o2a = new OutputArc<UserData>(t2, p3a);
	private OutputArc<UserData> o2b = new OutputArc<UserData>(t2, p3b);

	private InputArc<UserData> i3a = new InputArc<UserData>(p3a, t3);
	private InputArc<UserData> i3b = new InputArc<UserData>(p3b, t3);
	private OutputArc<UserData> o3 = new OutputArc<UserData>(t3, _end);

	// private InputArc<UserData> i4 = new InputArc<UserData>(p3a, t4);
	// private OutputArc<UserData> o4 = new OutputArc<UserData>(t4, _end);

	public SignupUserWorkflow(String label) {
		super(label);

		// set up any specific transition guards
		t3.setGuard(t3.new Guard() {

			@Override
			public boolean evaluate() {
				// enabled if either of p3a or p3b have a token
				return (p3a.getTokens().size() > 0 || p3b.getTokens().size() > 0);
			}
		});

		this.register(_start).register(p2).register(p3a).register(p3b).register(_end).register(t1).register(t2)
				.register(t3).register(i1).register(o1).register(i2).register(o2a).register(o2b).register(i3a)
				.register(o3).register(i3b);
	}

	@Override
	public Place<?> getSource() {
		return this._start;
	}

	@Override
	public Place getSink() {
		return this._end;
	}

}
